package l1j.server.Thread;

import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.server.Config;
import l1j.server.server.model.monitor.L1PcMonitor;

public class GeneralThreadPool {
	private static final Logger _log = Logger.getLogger(GeneralThreadPool.class.getName());
	private static GeneralThreadPool _instance;

 
	// 執行已提交的 Runnable 任務的對象。
	// 此接口提供一種將任務提交與每個任務將如何運行的機制（包括線程使用的細節、調度等）分離開來的方法。
	// 通常使用Executor 而不是顯式地創建線程。例如，可能會使用以下方法，
	// 而不是為一組任務中的每個任務調用new Thread(new(RunnableTask())).start()：
	private Executor _executor; // 通用的ExecutorService

	// 一個ExecutorService，可安排在給定的延遲後運行或定期執行的命令。
	private ScheduledExecutorService _scheduler; // 通用的ScheduledExecutorService
	private ScheduledExecutorService _pcScheduler; // 監測玩家專用的ScheduledExecutorService

	// ThreadPoolExecutor，它可另行安排在給定的延遲後運行命令，或者定期執行命令。
	// 需要多個輔助線程時，或者要求ThreadPoolExecutor 具有額外的靈活性或功能時，此類要優於Timer。
	//private ScheduledThreadPoolExecutor _poolExecutor;
	private static final int SCHEDULED_CORE_POOL_SIZE = 100;
	// (AutoUpdate:約6ms,ExpMonitor:極小)
	private final int _pcSchedulerPoolSize = 1 + Config.MAX_ONLINE_USERS / 5; // 每20人增加一個PoolSize
	

	public static GeneralThreadPool getInstance() {
		if (_instance == null) {
			_instance = new GeneralThreadPool();
		}
		return _instance;
	}

	private GeneralThreadPool() {
		/*	if (Config.THREAD_P_TYPE_GENERAL == 1) {
			_executor = Executors.newFixedThreadPool(Config.THREAD_P_SIZE_GENERAL);
		}
		else if (Config.THREAD_P_TYPE_GENERAL == 2) {
			_executor = Executors.newCachedThreadPool();
		}else {
			_executor = null;
		}*/
		// 創建一個可根據需要創建新線程的線程池，但是在以前構造的線程可用時將重用它們。
		_executor = Executors.newCachedThreadPool();

		// 常規(創建一個線程池，它可安排在給定延遲後運行命令或者定期地執行。)
		_scheduler = Executors.newScheduledThreadPool(SCHEDULED_CORE_POOL_SIZE, new PriorityThreadFactory("GerenalSTPool", Thread.NORM_PRIORITY));

		// PC(創建一個線程池，它可安排在給定延遲後運行命令或者定期地執行。)
		_pcScheduler = Executors.newScheduledThreadPool(_pcSchedulerPoolSize, new PriorityThreadFactory("PcMonitorSTPool", Thread.NORM_PRIORITY));
	}

	
	// Executor

	/**
	 * 使該線程開始執行；Java 虛擬機調用該線程的run 方法。
	 * @param r
	 */
	public void execute(Runnable r) {
		if (_executor == null) {
			Thread t = new Thread(r);
			t.start();
		}else {
			_executor.execute(r);
		}
	}
	/**
	 * 使該線程開始執行；Java 虛擬機調用該線程的run 方法。
	 * @param t
	 */
	public void execute(Thread t) {
		t.start();
	}

	/**
	 * 創建並執行在給定延遲後啟用的一次性操作。
	 * @param r 要執行的任務
	 * @param delay 從現在開始延遲執行的時間
	 * @return
	 */
	public ScheduledFuture<?> schedule(Runnable r, long delay) {
		try {
			if (delay <= 0) {
				_executor.execute(r);
				return null;
			}
			return _scheduler.schedule(r, delay, TimeUnit.MILLISECONDS);
		}
		catch (RejectedExecutionException e) {
			return null;
		}
	}
	/**
	 * 創建並執行一個在給定初始延遲後首次啟用的定期操作，後續操作具有給定的周期；<BR>
	 * 也就是將在initialDelay 後開始執行，然後在initialDelay+period 後執行，<BR>
	 * 接著在initialDelay + 2 * period 後執行，依此類推。 <BR>
	 * 如果任務的任何一個執行遇到異常，則後續執行都會被取消。 <BR>
	 * 否則，只能通過執行程序的取消或終止方法來終止該任務。 <BR>
	 * 如果此任務的任何一個執行要花費比其周期更長的時間，則將推遲後續執行，但不會同時執行。 <BR>
	 * <BR>
	 * @param r 要執行的任務
	 * @param initialDelay 首次執行的延遲時間
	 * @param period 連續執行之間的周期
	 * @return
	 */
	public ScheduledFuture<?> scheduleAtFixedRate(Runnable r, long initialDelay, long period) {
		return _scheduler.scheduleAtFixedRate(r, initialDelay, period, TimeUnit.MILLISECONDS);
	}

	// ScheduledExecutorService

	/**
	 * 創建並執行在給定延遲後啟用的一次性操作。
	 * @param r - 要執行的任務
	 * @param delay - 從現在開始延遲執行的時間
	 * @return
	 */
	public ScheduledFuture<?> pcSchedule(L1PcMonitor r, long delay) {
		try {
			if (delay <= 0) {
				// 在未來某個時間執行給定的命令。
				// 該命令可能在新的線程、已入池的線程或者正調用的線程中執行，這由Executor 實現決定。
				_executor.execute(r);
				return null;
			}
			// 創建並執行在給定延遲後啟用的一次性操作。
			return _pcScheduler.schedule(r, delay, TimeUnit.MILLISECONDS);
		}
		catch (RejectedExecutionException e) {
			return null;
		}
	}

	// ScheduledThreadPoolExecutor

	/**
	 * 創建並執行一個在給定初始延遲後首次啟用的定期操作，後續操作具有給定的周期；
	 * 也就是將在initialDelay 後開始執行，然後在initialDelay+period 後執行，
	 * 接著在initialDelay + 2 * period 後執行，依此類推。
	 * 如果任務的任何一個執行遇到異常，則後續執行都會被取消。
	 *
	 * 否則，只能通過執行程序的取消或終止方法來終止該任務。
	 * 如果此任務的任何一個執行要花費比其周期更長的時間，則將推遲後續執行，但不會同時執行。
	 *
	 * @param command - 要執行的任務
	 * @param initialDelay - 首次執行的延遲時間
	 * @param period - 連續執行之間的周期
	 * @return
	 */
	public ScheduledFuture<?> pcScheduleAtFixedRate(L1PcMonitor r, long initialDelay, long period) {
		return _pcScheduler.scheduleAtFixedRate(r, initialDelay, period, TimeUnit.MILLISECONDS);
	}
	
	// TIMER

	/**
	 * 安排指定的任務在指定的延遲後開始進行重複的固定速率執行。<BR>
	 * 以近似固定的時間間隔（由指定的週期分隔）進行後續執行。<BR>
	 * 在固定速率執行中，根據已安排的初始執行時間來安排每次執行。<BR>
	 * 如果由於任何原因（如垃圾回收或其他後臺活動）而延遲了某次執行，<BR>
	 * 則將快速連續地出現兩次或更多的執行，從而使後續執行能夠“追趕上來”。<BR>
	 * 從長遠來看，執行的頻率將正好是指定週期的倒數（假定 Object.wait(long) 所依靠的系統時鐘是準確的）。<BR>
	 *<BR>
	 * 固定速率執行適用於那些對絕對 時間敏感的重複執行活動，<BR>
	 * 如每小時准點打鐘報時，或者在每天的特定時間運行已安排的維護活動。<BR>
	 * 它還適用於那些完成固定次數執行的總計時間很重要的重複活動，<BR>
	 * 如倒計時的計時器，每秒鐘滴答一次，共 10 秒鐘。<BR>
	 * 最後，固定速率執行適用於安排多個重複執行的計時器任務，這些任務相互之間必須保持同步。<BR>
	 * <BR>
	 * @param task - 所要安排的任务。
	 * @param delay - 执行任务前的延迟时间，单位是毫秒。
	 * @param period - 执行各后续任务之间的时间间隔，单位是毫秒。
	 * @return 
	 */
	public Timer aiScheduleAtFixedRate(final TimerTask task, final long delay, final long period) {
		try {
			final Timer timer = new Timer();
			timer.scheduleAtFixedRate(task, delay, period);
			return timer;

		} catch (final RejectedExecutionException e) {
		}
		return null;
	}


	// ThreadPoolManager 借用
	/**
	 * 根據需要創建新線程的對象。
	 * 使用線程工廠就無需再手工編寫對new Thread 的調用了，從而允許應用程序使用特殊的線程子類、屬性等等。
	 * @author daien
	 *
	 */
	private class PriorityThreadFactory implements ThreadFactory {

		private final int _prio;

		private final String _name;

		private final AtomicInteger _threadNumber = new AtomicInteger(1);

		private final ThreadGroup _group;

		/**
		 * PriorityThreadFactory
		 * @param name 線程名稱
		 * @param prio 優先等級
		 */
		public PriorityThreadFactory(String name, int prio) {
			_prio = prio;
			_name = name;
			_group = new ThreadGroup(_name);
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.util.concurrent.ThreadFactory#newThread(java.lang.Runnable)
		 */

		@Override
		public Thread newThread(Runnable r) {
			Thread t = new Thread(_group, r);
			t.setName(_name + "-" + _threadNumber.getAndIncrement());
			t.setPriority(_prio);
			return t;
		}

		@SuppressWarnings("unused")
		public ThreadGroup getGroup() {
			return this._group;
		}
	}
	/**
	 * 试图取消对此任务的执行。
	 * 如果任务已完成、或已取消，或者由于某些其他原因而无法取消，则此尝试将失败。
	 * 当调用 cancel 时，如果调用成功，而此任务尚未启动，则此任务将永不运行。
	 * 如果任务已经启动，则 mayInterruptIfRunning 参数确定是否应该以试图停止任务的方式来中断执行此任务的线程。 
	 * 此方法返回后，对 isDone() 的后续调用将始终返回 true。
	 * 如果此方法返回 true，则对 isCancelled() 的后续调用将始终返回 true。 
	 * 
	 * @param future - 一个延迟的、结果可接受的操作，可将其取消。
	 * @param mayInterruptIfRunning - 如果应该中断执行此任务的线程，则为 true；否则允许正在运行的任务运行完成 
	 */
	public void cancel(final ScheduledFuture<?> future, boolean mayInterruptIfRunning) {
		try {
			future.cancel(mayInterruptIfRunning);

		} catch (final RejectedExecutionException e) {
			_log.log(Level.SEVERE ,e.getLocalizedMessage(), e);
		}
	}
	
}
